<?php

namespace app\api\controller;
use app\model\OrderItemsModel;
use app\model\OrdersModel;
use app\model\ProductSalesSpecsModel;
use app\model\ProductsModel;
use app\model\UserFbLogModel;
use EasyWeChat\Factory;
use Exception;
use think\App;
use think\facade\Db;


class Pay extends Base {
    private $orderModel;

    private $orderItemModel;

    private $userFbLogModel;

    private $order_id;

    private $uid;

    private $appName;

    private $token;


    public function __construct(App $app)
    {
        parent::__construct($app);

        $this->appName = config("app.app_name");

        $this->orderModel = new OrdersModel();

        $this->userFbLogModel = new UserFbLogModel();

        $this->orderItemModel = new OrderItemsModel();

        $this->req = request()->param();

    }


    /*
     * 微信支付
     *
     * */
    public function wxPay(){

        $this->order_id = isset($this->req["order_id"]) ? trim($this->req["order_id"]) : "" ;

        $this->uid = $this->isLogin();

        $this->token = trim(request()->header("token"));

        if(empty($this->order_id)){
            return $this->fail("参数错误:订单号不能为空");
        }

        if(!$this->orderModel->isUserOrder($this->uid,$this->order_id)){
            return $this->fail("订单不存在");
        }

        if(isUnionOrderId($this->order_id) &&  $this->orderModel->checkUnionOrderIsHavePay($this->order_id)){
            return $this->fail("存在已支付订单，不可支付");
        }

        $ids = $this->orderModel->getOrderByPOrderId($this->order_id);

        foreach ($ids as $id){
            if($this->orderModel->getOrderStatus($id) != 0){
                return $this->fail("订单状态错误");
            }

            if($this->orderModel->getOrderPayStatus($id) == 1){
                return $this->fail("订单已支付");
            }
        }

        $productSnapshoList = $this->orderItemModel->getProductSnapshoList($ids);

        $productInfo = json_decode($productSnapshoList[0]["product_snapshot"],true);
        $payBody = count( $productSnapshoList) > 1 ?  $productInfo["product_name"] . "（等多个商品）" : $productInfo["product_name"];
        $total_amount = $this->orderModel->getUnionOrderTotalAmount($this->order_id);
        $wxPayConfig = config("wxpay");
        $wxPayConfig['cert_path'] =  app()->getRootPath().$wxPayConfig['cert_path'];
        $wxPayConfig['key_path'] =  app()->getRootPath().$wxPayConfig['key_path'];

        $app = Factory::payment($wxPayConfig);

        $order = [
            'trade_type'       => 'JSAPI', // 小程序支付使用 'JSAPI'
            'body'             => $payBody,
            'out_trade_no'     => $this->order_id,
            'total_fee'        => $total_amount, // 单位：分
            'notify_url'       => $wxPayConfig['notify_url'], // 支付结果通知网址
            'openid'           => $this->token, // 用户的openid
        ];


        try {
            $result = $app->order->unify($order);

            if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
                $prepayId = $result['prepay_id'];
                $jssdk = $app->jssdk;
                $config = $jssdk->sdkConfig($prepayId); // 返回给前端用于调用微信支付接口的配置
                return $this->succ($config);
            } else {
                return $this->fail("支付失败：".$result);
            }
        }catch (\Exception $e){
            return $this->fail("支付失败：".$e->getMessage());
        }

    }


    /*
     * 回调
    {
    "appid": "wx41b04cd310240ded",
    "bank_type": "OTHERS",
    "cash_fee": "1",
    "fee_type": "CNY",
    "is_subscribe": "N",
    "mch_id": "1682239761",
    "nonce_str": "66ac7f0e3b4ca",
    "openid": "oehMM7TAixN_YgYnADUGGIN_qMlw",
    "out_trade_no": "L1722580728955950401944",
    "result_code": "SUCCESS",
    "return_code": "SUCCESS",
    "sign": "F9615131170994F291622489C0C99EFA",
    "time_end": "20240802143915",
    "total_fee": "1",
    "trade_type": "JSAPI",
    "transaction_id": "4200002297202408021856491703"
}
     * */

    public function notify(){

        $wxPayConfig = config("wxpay");
        $wxPayConfig['cert_path'] =  app()->getRootPath().$wxPayConfig['cert_path'];
        $wxPayConfig['key_path'] =  app()->getRootPath().$wxPayConfig['key_path'];
        $app = Factory::payment($wxPayConfig);

        $response = $app->handlePaidNotify(function($message, $fail) {
            //记录日志
            addWxPayLog("wxpay_notify.txt",json_encode($message,256));

            // 处理订单逻辑
            $order_id = $message['out_trade_no'];

            if ($message['return_code'] === 'SUCCESS') {
                if ($message['result_code'] === 'SUCCESS') {

                    $tryNum = 0;
                    $success = false;
                    do {
                        try {
                            // 尝试执行两个关键操作
                            $orderUpdateRes = $this->orderModel->markAsPaid($order_id, $message);

                            if (isUnionOrderId($order_id)) {
                                $where['p_order_id'] = $order_id;
                            } else {
                                $where['order_id'] = $order_id;
                            }

                            if( $this->userFbLogModel->getTotal($where) > 0){
                                $fbStatusRes = $this->userFbLogModel->updateAll($where, ["fb_status" => 1]);
                            }else{
                                $fbStatusRes = true;
                            }

                            // 只有当两个操作都成功时，才算整体成功
                            if ($orderUpdateRes && $fbStatusRes) {
                                $success = true; // ✅ 标记成功，退出循环
                            } else {
                                // 如果某个操作返回 false（比如影响行数为0），说明失败
                                addWxPayLog("wxpay_notify_error.txt", "用户支付成功->部分操作未执行成功: success1={$success1}, success2={$success2}");
                                $tryNum++;
                                sleep(1); // 避免高频重试
                            }

                        } catch (Exception $e) {
                            $tryNum++;
                            addWxPayLog("wxpay_notify_error.txt", "用户支付成功->更新支付状态异常: 第{$tryNum}次重试 | 错误: " . $e->getMessage() . " | Trace: " . $e->getTraceAsString());
                            sleep(1); // 等待1秒再重试
                        }

                    } while (!$success && $tryNum < 20);

                        // ✅ 最终判断：是否真的成功
                    if (!$success) {
                        // ⚠️ 严重错误：20次重试都失败，需要告警
                        addWxPayLog("wxpay_notify_fatal.txt", "【严重】用户支付成功，但订单/捐款状态更新失败！order_id: {$order_id}, 请人工核查！");
                        // 可选：触发企业微信/钉钉告警
                        // sendAlertToAdmin("支付回调状态更新失败", "order_id: $order_id");
                    }

                    //更新销量
                    $ids = $this->orderModel->getOrderByPOrderId($order_id);
                    foreach ($ids as $id){
                        $specsList = (new OrderItemsModel())->getProductSaleNumList($id);
                        $productSalesSpecsModel = new ProductSalesSpecsModel();
                        foreach ($specsList as $spec){
                            $productSalesSpecsModel->incrProductSalesNum($spec["spec_id"],$spec["spec_num"]);
                        }

                        $productModel = new ProductsModel();
                        foreach ($specsList as $spec){
                            $productModel->incrProductSalesNum($spec["product_id"],$spec["spec_num"]);
                        }

                    }

                } elseif ($message['result_code'] === 'FAIL') {

                    $tryNum = 0;
                    $success = false;

                    do {
                        try {
                            // 用户支付失败
                            $success =  $this->orderModel->markAsFailed($order_id,$message);
                        } catch (Exception $e) {
                            $tryNum++;
                            // 可选：记录错误日志或发送通知给管理员
                            addWxPayLog("wxpay_notify_error.txt","用户支付失败->更新支付状态异常:".$e->getMessage());
                            // 可选：等待一段时间后再重试，避免快速重复
                            sleep(1); // 等待1秒再重试
                        }
                    } while (!$success && $tryNum < 20);
                }
            } else {
                return $fail('通信失败，请稍后再通知我');
            }

            return true; // 返回处理完成
        });

        $response->send(); // 发送响应给微信支付
    }

}